#pragma once

#include "..\\Vertex.h"
#include "Joint.h"
#include <dae.h>
#include <dom.h>
#include <dom/domCOLLADA.h>
#include "ColladaLibs.h"
#include <string>
#include <vector>
using namespace std;

#include "..\\..\\Utility\\D3D\\D3DUtilityFunction.h"
#include "..\\MeshRender.h"
class SkinnedMesh : public CMeshRender
{
public:
	#pragma region //COLLADA members
	//<controller>
	daeElement* controller;
	//<geometry>
	daeElement* geometry;
	//Root <node> for skeleton
	daeElement* rootJoint;
	//Component Vertex Data, to be compiled into Vertices later...
	vector<D3DXVECTOR3> Positions;
	vector<D3DXVECTOR2> UVs;
	vector<D3DXVECTOR3> Normals;
	vector<D3DXVECTOR3> Tangents;
	vector<D3DXVECTOR3> BiNormals;
	vector<SkinIndex> boneIndices;
	vector<SkinWeight> Weights;
	//Set it so COLLADALoader can access privates
	//friend class COLLADALoader;
	//Combine the component vertex data to Vertices array
	void combineComponents()
	{
		for(unsigned int i = 0; i < Positions.size(); i++) 
			Vertices.push_back(VertexNormUVTangSkinned(Positions[i], Normals[i], UVs[i], Tangents[i], BiNormals[i], boneIndices[i], Weights[i]));
	}

	//Make Animation list
	void combineJointAnimations()
	{
		//Put all the Animations together
		for(unsigned int i = 0; i < Joints.size(); i++){
			for(unsigned int z = 0; z < Joints[i].Animations.size(); z++){
				Animations.push_back(Joints[i].Animations[z]);
			}
		}

		//Do a simple Bubble Sort by Time
		for(unsigned int i = 0; i < Animations.size(); i++){
			for(unsigned int j = 0; j < i; j++){
				if(Animations[i].Time < Animations[j].Time){
					JointAnimationKey temp = Animations[i];
					Animations[i] = Animations[j];
					Animations[j] = temp;
				}
			}
		}

		//Set Matrix Pallette to appropiate size, this is to avoid all that extra cpu work every frame
		for(unsigned int i = 0; i < Joints.size(); i++){
			boneTransforms.push_back(D3DXMATRIX());
			worldTransforms.push_back(D3DXMATRIX());
			Pallette.push_back(D3DXMATRIX());
		}
	}

	#pragma endregion

	//Accumulated time for the animation
	float accumulatedTime;
	//Bone Transforms
	vector<D3DXMATRIX> boneTransforms;
	//World Transforms
	vector<D3DXMATRIX> worldTransforms;
	//Matrix Pallette
	vector<D3DXMATRIX> Pallette;
public:
	//Name
	string Name;
	//Root Transform Matrix
	D3DXMATRIX RootTransform;
	//BindShape Matrix
	D3DXMATRIX BindShape;
	//Joints
	vector<Joint> Joints;
	//Time sorted Animation Key list
	vector<JointAnimationKey> Animations;
	//Combined Vertex Data, ready for Vertex Buffer
	vector<VertexNormUVTangSkinned> Vertices;
	//Index data, ready for Index Buffer
	vector<unsigned int> Indices;
	//Constructor
	SkinnedMesh();
	SkinnedMesh(string Name, D3DXMATRIX RootTransform);
	//Destructor
	virtual ~SkinnedMesh()
	{
		Positions.clear();
		UVs.clear();
		Normals.clear();
		Tangents.clear();
		BiNormals.clear();
		boneIndices.clear();
		Weights.clear();
		boneTransforms.clear();
		worldTransforms.clear();
		Pallette.clear();
		Joints.clear();
		Animations.clear();
		Vertices.clear();
		Indices.clear();
		OnD3D11DestroyDevice(NULL);
	}
	//Placeholder for future improvement
	void SetVType(enum VERTEXTYPE VType);
	//OnDeviceReset
	virtual HRESULT OnD3D11CreateDevice( ID3D11Device* pd3dDevice, ID3DX11EffectTechnique* pTech,
		const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, CDirectoryUtil* pDirUtil, void* pUserContext);
	//Update with delta time
	void Update(float dt);
	//Draw
	virtual void Render(ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, ID3DX11Effect* pEffect, 
						ID3DX11EffectTechnique* pRenderTech, enum RENDERMESHTECH iMeshType, const D3DXMATRIX& mWorldCamera, 
						double fTime, float fElapsedTime, void* pUserContext);
private:
	//Step Animation
	void StepAnimate();
	//Linear Animation
	void LinearAnimate();	
	//Calculate Skin
	void CalculateSkin();
};
